home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MACD 5
/
MACD 5.bin
/
workbench
/
wb
/
czesc_2
/
memmometer
/
src
/
mm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-06
|
56KB
|
1,768 lines
/* : ai=0 bk=0 ts=8 */
#ifdef TALKTOREXX
/*
* MinRexx include file
*/
char *VERSION = "MemMometer, Version 2.40 w ARexx" ;
#include "minrexx.h"
#else
char *VERSION = "MemMometer, Version 2.39" ;
#endif
#include "mm.h"
#define FREEPEN -1L /* workbench screen default colors */
#define REQ_WINDOW_WIDTH 319L /* width of warning requester window */
#define REQ_WINDOW_HEIGHT 79L /* height of warning requester window */
#define SOK 0x001f /* memory allocation control masks */
#define S1 0x0001
#define S2 0x0002
#define S4 0x0004
#define S8 0x0008
#define SA 0x0010
#define C1 0xfffe
#define C2 0xfffd
#define C4 0xfffb
#define C8 0xfff7
#define CA 0xffef
#define AARRRGH 20L /* hang 20, cats, we're startin ta curl! */
#define EXTENSION 16L /* allocation request increment */
#define FRAGS FALSE /* frags mode control boolian */
#define WARPS TRUE /* warps mode control boolian */
#define EVENMASK 0x7ffffffe /* used to prevent odd address traps */
#define CLIHEIGHT 200L /* window scaling stuff */
#define SIZEGAD 9L
#define DRAGBAR 10L
#define BORDER 2L
#define WINW 16L /* initial window width */
#define WINH (long)(CLIHEIGHT - SIZEGAD - DRAGBAR) /* initial win height */
#define MINH 81L /* shortest allowable window */
#define MAXH 576L /* longest allowable window */
#define BART 1L /* title bar F text location */
#define BARH (long)(WINH - SIZEGAD - DRAGBAR) /* bar height */
#define BARS (long)(BARH + 1) /* number of memory items to allocate */
#define BARB (long)(BARH + DRAGBAR - 1) /* bottom of mercury column */
#define BARE (long)(BARB + BORDER) /* bar end E text position */
#define BARW (long)(((WINW - (2 * BORDER)) / 3) - 1) /* 3 memfragmometers */
#define LEFT BORDER /* SLOW : since we're syncopated, we */
#define MIDDLE (LEFT + BARW + 1) /* SLOW-FAST : do it going from bar */
#define RIGHT (MIDDLE + BARW + 1) /* FAST :to bar at an irregular pace */
#define RTEXT - 4L /* offset for three char E/F text from left edge */
#define STARTVAL 64L /* start by getting enough storage for a few frags */
#define TMARK 100000L /* timer granule in microseconds */
#define TICKIES (long)(1000000/TMARK) /* number of TMARKS per second */
/* typedef short BOOL */ /* this is in include/exec/types.h */
struct IntuitionBase *IntuitionBase=NULL ;
struct Window *window ;
struct IntuiMessage *NewMessage;
/* struct IntuiMessage *GetMsg(); */ /* in functions.h */
struct GfxBase *GfxBase=NULL ;
struct IOStdReq *timermsg=NULL;
struct MsgPort *timerport=NULL;
ULONG timerbit=NULL;
extern void InitProjItems(); /* this stuff is in the mminit section */
extern void InitSetupItems();
extern void InitPrioItems();
extern void InitChipItems();
extern void InitChipAItems();
extern void InitSFItems();
extern void InitSFAItems();
extern void InitFastItems();
extern void InitFastAItems();
extern void InitMenu();
extern void StartMenus();
#ifdef TALKTOREXX
/*
* Menu Check Mark alteration for Rexx
*/
extern void DoCheckMenus();
#endif
BOOL p_mode = FRAGS; /* preset frags mode = 0, warps mode = 1 */
/* note: mode preset used as request for */
/* change to warps mode after the */
/* first pass with frags mode set! */
long p_rate = 2; /* preset sample interval, secs see menu */
long p_priority = 0; /* preset priority, range -128 to +127 */
/* note: pri greater than zero is risky! */
/* keep in mind AmigaDOS priorities: */
/* input.device 20, FileSystem 10, and */
/* trackdisk.device, CON: 5 also if MM */
/* is started from a CLI without the Run */
/* then that CLI inherits MM's priority! */
long p_chip = 512; /* preset chip mem size, kbytes see menu */
long p_chipa = 0; /* preset chip mem address, kb see menu */
long p_sf = 0; /* preset slowfast mem size, kb see menu */
long p_sfa = 2048; /* preset slowfast mem addr, kb see menu */
long p_fast = 0; /* preset fast mem size, mbytes see menu */
long p_fasta = -1; /* preset fast mem addr, mbytes see menu */
/* zero or neg fasta is offset below the */
/* A3000 fast ram ceiling, aka 0x8000000 */
static BOOL enforcer; /* uninitialized for enforcer fix */
static BOOL enforced; /* uninitialized for enforcer fix */
static BOOL pmchange; /* uninitialized for mode change */
static BOOL cschange; /* uninitialized for chip mem chg */
static BOOL mode; /* uninitialized for mode control */
static BOOL mmode; /* uninitialized for mode menu */
static long delayval; /* uninitialized for delay menu */
static long priority; /* uninitialized for prioritymenu */
static long basepri; /* uninitialized for priorityincr */
static long cmemsize; /* uninitialized for chip menu */
static long cmembase; /* uninitialized for chipa menu */
static long sfmemsize; /* uninitialized for sf menu */
static long sfmembase; /* uninitialized for sfa menu */
static long fmemsize; /* uninitialized for fast menu */
static long fmembase; /* uninitialized for fasta menu */
static USHORT log ; /* memory allocation success flags */
static BOOL things_are_cool = TRUE ; /* tells when to close the window */
static BOOL intsig = FALSE ; /* intuition message detector */
static USHORT chgflag = TRUE ; /* menu request to adjust columns */
static long chip[3], fast[3] ; /* place to keep mem header pointers */
static ULONG *chunkv ; /* demand allocated for frag chunks */
static ULONG *sizev ; /* demand allocated for frag sizes */
static ULONG *csum ; /* a col's height worth of checksums */
static ULONG *oldcsum ; /* same height worth of old checksums */
static USHORT *cell; /* 1 cell per pixel height of mercury */
static long xl, xr ; /* used to Draw() memmometer segments */
static long frags = STARTVAL ; /* # of demand allocated frag items */
static long bars = BARS ; /* # of demand allocated column items */
static long barh = BARH ; /* EVEN #'d height of mercury column */
static long barb = BARB ; /* bottom position of mercury column */
static short ticker = TICKIES ; /* initialized delay tick variable */
/* struct RastPort *rp ; */ /* wonder why we don't need this... ? */
static struct TextAttr myfont = {
(STRPTR) "topaz.font",
TOPAZ_EIGHTY,
0,
0
};
/* E newsize gadget refresh text */
static char ebuf[4] = " E " ;
static struct IntuiText e_text = {
BAKP, SHAP,
JAM2,
0, BARE,
&myfont,
(UBYTE *)ebuf,
NULL
};
/* F title refresh text */
static char fbuf[4] = " F " ;
static struct IntuiText f_text = {
BAKP, SHAP,
JAM2,
0, BART,
&myfont,
(UBYTE *)fbuf,
&e_text
};
static struct NewWindow newwindow = {
0, /* left edge */
10, /* top edge */
WINW, /* width */
WINH, /* height */
0, /* detail pen */
1, /* block pen */
MENUPICK | NEWSIZE, /* messages */
/* WINDOWDEPTH | WINDOWCLOSE */ /* don't use these gads */
WINDOWDRAG | WINDOWSIZING | NOCAREREFRESH, /* add a few gadgets */
NULL, /* no custom gadgets */
NULL, /* default checkmark */
(UBYTE *)"F", /* title */
NULL, /* initialize this! */
NULL, /* use screen bitmap */
WINW, MINH, WINW, MAXH, /* min and max sizes */
WBENCHSCREEN } ; /* use workbench screen */
#ifdef TALKTOREXX
/*
* The following are program global definitions for our own Rexx functions.
*/
#define TWOMEG 2097152L
#define EIGHTMEG 8388608L
#define CZERO 12582912L
#define EZERO 14680064L
#define SEVENOH 117440512L
/*
* If we are talking to REXX, we need these additional locals.
*/
long rexxbit ;
char firstcommand[256] ;
int dechecked = 0 ; /* Menu check mark flags now invalidated */
int rechecked = 0 ; /* Menu check mark flags now re-validated */
static BOOL refrshpre ; /* Marks Rexx request redo preset variables */
/*
* These are our REXX functions, as defined at the bottom of the file.
*/
void rexxfront(), rexxback(), rexxquit(), rexxmode(), rexxrate(),
rexxpriority(), rexxchipa(), rexxchip(), rexxsfa(), rexxsf(),
rexxfasta(), rexxfast(), rexxversion() ;
void disp() ;
/*
* Here is our command association list. Note that in this case,
* we are setting the userdata field to be a function to call.
* Dispatch will still take place through disp(), so common head
* and tail stuff can go there.
*
* Commands are all lower case, so we match either upper or lower.
* (This is a requirement of minrexx.)
*/
struct rexxCommandList rcl[] = {
{ "front", &rexxfront },
{ "back", &rexxback },
{ "quit", &rexxquit },
{ "mode", &rexxmode },
{ "rate", &rexxrate },
{ "priority", &rexxpriority },
{ "chipa", &rexxchipa },
{ "chip", &rexxchip },
{ "sfa", &rexxsfa },
{ "sf", &rexxsf },
{ "fasta", &rexxfasta },
{ "fast", &rexxfast },
{ "version", &rexxversion },
{ NULL, NULL, } } ;
#endif
void initmenus()
{
(void) InitProjItems(); /* Initialize the menu items */
(void) InitSetupItems();
(void) InitPrioItems();
(void) InitChipItems();
(void) InitChipAItems();
(void) InitSFItems();
(void) InitSFAItems();
(void) InitFastItems();
(void) InitFastAItems();
(void) InitMenu();
(void) StartMenus();
}
void handle_MENUPICK( class, code )
unsigned long class;
unsigned int code;
{
unsigned int menunum, itemnum, subnum;
if (code == MENUNULL) return;
menunum = MENUNUM( code );
itemnum = ITEMNUM( code );
subnum = SUBNUM( code );
chgflag = TRUE;
switch( menunum ) {
case 0:
switch( itemnum ) {
case 0:
WindowToFront(window);
break;
case 1:
WindowToBack(window);
break;
case 2:
things_are_cool = FALSE; /* Quit */
break;
} /* end of switch ( Project itemnum ) */
break;
case 1:
switch( itemnum ) {
case 0:
switch( subnum ) {
case 0:
if ( mode == WARPS ) pmchange = TRUE ;
mode = FRAGS ; /* Frags mode */
mmode = FALSE ; /* cancel any pending request */
break;
case 1:
mmode = TRUE ; /* Warps request */
pmchange = TRUE ; /* denotes request came from menu */
break;
/* end of switch ( Mode subnum ) */
}
break;
case 1:
switch( subnum ) {
case 0:
delayval = 1;
break;
case 1:
delayval = 2;
break;
case 2:
delayval = 5;
break;
case 3:
delayval = 10;
break;
/* end of switch ( Freq subnum ) */
}
break;
/* end of switch ( Setup itemnum ) */
}
break;
case 2:
switch( itemnum ) {
case 0:
priority = basepri;
break;
case 1:
priority = priority - 1;
break;
case 2:
priority = priority + 1;
break;
case 3:
priority = -99;
basepri = priority;
break;
case 4:
priority = -75;
basepri = priority;
break;
case 5:
priority = -50;
basepri = priority;
break;
case 6:
priority = -25;
basepri = priority;
break;
case 7:
priority = -20;
basepri = priority;
break;
case 8:
priority = -15;
basepri = priority;
break;
case 9:
priority = -10;
basepri = priority;
break;
case 10:
priority = -5;
basepri = priority;
break;
case 11:
priority = 0;
basepri = priority;
break;
case 12:
priority = 5;
basepri = priority;
break;
case 13:
priority = 10;
basepri = priority;
break;
case 14:
priority = 15;
basepri = priority;
break;
case 15:
priority = 20;
basepri = priority;
break;
}
/* end of switch ( Priority itemnum ) */
break;
case 3:
switch( itemnum ) {
case 0:
cmemsize = 0x000000;
enforcer = 0;
enforced = 0;
break;
case 1:
cmemsize = 0x040000;
cschange = TRUE ;
break;
case 2:
cmemsize = 0x080000;
cschange = TRUE ;
break;
case 3:
cmemsize = 0x0c0000;
cschange = TRUE ;
break;
case 4:
cmemsize = 0x100000;
cschange = TRUE ;
break;
case 5:
cmemsize = 0x180000;
cschange = TRUE ;
break;
case 6:
cmemsize = 0x200000;
cschange = TRUE ;
break;
}
/* end of switch ( Chip Size itemnum ) */
break;
case 4:
switch( itemnum ) {
case 0:
cmembase = 0x000000;
if ( mode == TRUE ) {
enforcer = TRUE;
}
break;
case 1:
cmembase = 0x040000;
break;
case 2:
cmembase = 0x080000;
break;
case 3:
cmembase = 0x0c0000;
break;
case 4:
cmembase = 0x100000;
break;
case 5:
cmembase = 0x180000;
break;
case 6:
cmembase = 0xc00000;
break;
case 7:
cmembase = 0xc40000;
break;
case 8:
cmembase = 0xc80000;
break;
case 9:
cmembase = 0xcc0000;
break;
case 10:
cmembase = 0xd00000;
break;
case 11:
cmembase = 0xd40000;
break;
}
/* end of switch ( Chip Addr itemnum ) */
break;
case 5:
if (mode == WARPS) mmode = TRUE ;
switch( itemnum ) {
case 0:
sfmemsize = 0x000000;
break;
case 1:
sfmemsize = 0x040000;
break;
case 2:
sfmemsize = 0x080000;
break;
case 3:
sfmemsize = 0x0c0000;
break;
case 4:
sfmemsize = 0x100000;
break;
case 5:
sfmemsize = 0x180000;
break;
case 6:
sfmemsize = 0x200000;
break;
case 7:
sfmemsize = 0x300000;
break;
case 8:
sfmemsize = 0x400000;
break;
case 9:
sfmemsize = 0x600000;
break;
case 10:
sfmemsize = 0x800000;
break;
}
/* end of switch ( SF Size itemnum ) */
break;
case 6:
if (mode == WARPS) mmode = TRUE ;
switch( itemnum ) {
case 0:
sfmembase = 0x200000;
break;
case 1:
sfmembase = 0x240000;
break;
case 2:
sfmembase = 0x280000;
break;
case 3:
sfmembase = 0x2c0000;
break;
case 4:
sfmembase = 0x300000;
break;
case 5:
sfmembase = 0x400000;
break;
case 6:
sfmembase = 0x500000;
break;
case 7:
sfmembase = 0x600000;
break;
case 8:
sfmembase = 0x700000;
break;
case 9:
sfmembase = 0x800000;
break;
case 10:
sfmembase = 0x900000;
break;
case 11:
sfmembase = 0xc00000;
break;
case 12:
sfmembase = 0xc40000;
break;
case 13:
sfmembase = 0xc80000;
break;
case 14:
sfmembase = 0xcc0000;
break;
case 15:
sfmembase = 0xd00000;
break;
}
/* end of switch ( SF Addr itemnum ) */
break;
case 7:
if (mode == WARPS) mmode = TRUE ;
switch( itemnum ) {
case 0:
fmemsize = 0x000000;
break;
case 1:
fmemsize = 0x040000;
break;
case 2:
fmemsize = 0x080000;
break;
case 3:
fmemsize = 0x0c0000;
break;
case 4:
fmemsize = 0x100000;
break;
case 5:
fmemsize = 0x200000;
break;
case 6:
fmemsize = 0x300000;
break;
case 7:
fmemsize = 0x400000;
break;
case 8:
fmemsize = 0x500000;
break;
case 9:
fmemsize = 0x600000;
break;
case 10:
fmemsize = 0x700000;
break;
case 11:
fmemsize = 0x800000;
break;
case 12:
fmemsize = 0xa00000;
break;
case 13:
fmemsize = 0xc00000;
break;
case 14:
fmemsize = 0xe00000;
break;
case 15:
fmemsize = 0x1000000;
break;
}
/* end of switch ( Fast Size itemnum ) */
break;
case 8:
if (mode == WARPS) mmode = TRUE ;
switch( itemnum ) {
case 0:
fmembase = 0x7f00000;
break;
case 1:
fmembase = 0x7e00000;
break;
case 2:
fmembase = 0x7d00000;
break;
case 3:
fmembase = 0x7c00000;
break;
case 4:
fmembase = 0x7a00000;
break;
case 5:
fmembase = 0x7800000;
break;
case 6:
fmembase = 0x7600000;
break;
case 7:
fmembase = 0x7400000;
break;
case 8:
fmembase = 0x7200000;
break;
case 9:
fmembase = 0x7000000;
break;
case 10:
fmembase = 0x9000000;
break;
case 11:
fmembase = 0x8c00000;
break;
case 12:
fmembase = 0x8800000;
break;
case 13:
fmembase = 0x8400000;
break;
case 14:
fmembase = 0x8200000;
break;
case 15:
fmembase = 0x8000000;
break;
}
/* end of switch ( Fast Addr itemnum ) */
break;
}
/* end of switch ( menunum ) */
}
void wrack_sploot() /* this subprogram cashes in the chips in bad times */
{
if (log != 0) {
if (log & SA) {
(void) FreeMem(oldcsum, (long)(sizeof(ULONG) * bars)) ;
log = log & CA ;
}
if (log & S8) {
(void) FreeMem(csum, (long)(sizeof(ULONG) * bars)) ;
log = log & C8 ;
}
if (log & S4) {
(void) FreeMem(sizev, (long)(sizeof(long) * frags)) ;
log = log & C4 ;
}
if (log & S2) {
(void) FreeMem(chunkv, (long)(sizeof(long) * frags)) ;
log = log & C2 ;
}
if (log & S1) {
(void) FreeMem(cell, (long)(sizeof(USHORT) * bars)) ;
log = log & C1 ;
}
frags = 0;
bars = 0;
}
}
SetTimer(sec, micro, timermsg)
ULONG sec, micro;
struct IOStdReq *timermsg;
/* This routine simply sets the timer to interrupt us after secs.micros */
{
timermsg->io_Command = TR_ADDREQUEST; /* add a new timer request */
timermsg->io_Actual = sec; /* seconds */
timermsg->io_Length = micro; /* microseconds */
SendIO((struct IORequest *)timermsg); /* post a request to the timer */
}
void cleanup() {
if (timerport) {
Wait(timerbit);
GetMsg(timerport);
CloseDevice((struct IORequest *)timermsg);
DeleteStdIO(timermsg);
DeletePort(timerport);
}
if (GfxBase) CloseLibrary((struct Library *)GfxBase) ;
if (window) CloseWindow(window) ;
if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase) ;
wrack_sploot() ;
exit(AARRRGH) ;
}
void inittimer()
{
if(!(timerport = (struct MsgPort *)CreatePort(0L, 0L)))cleanup();
if(!(timermsg = (struct IOStdReq *)CreateStdIO(timerport)))cleanup();
if (OpenDevice((UBYTE *)TIMERNAME, UNIT_VBLANK, (struct IORequest *)timermsg, 0L))cleanup();
timerbit = 1L << timerport->mp_SigBit ;
SetTimer(1L, 0L, timermsg); /* set for first message */
}
void handle_NEWSIZE() /* short term allocations cashed in then realloc'd */
{ /* when user hits gadget but doesn't resize window */
if (log & SA) {
(void) FreeMem(oldcsum, (long)(sizeof(ULONG) * bars)) ;
log = log & CA ;
}
if (log & S8) {
(void) FreeMem(csum, (long)(sizeof(ULONG) * bars)) ;
log = log & C8 ;
}
if (log & S1) {
(void) FreeMem(cell, (long)(sizeof(USHORT) * bars)) ;
log = log & C1 ;
barh = window->Height - SIZEGAD - DRAGBAR ; /* recalculate height */
barb = window->Height - SIZEGAD - 1 ; /* get new bar base position */
bars = barh + 1 ; /* number of storage frames to be reserved */
if ((cell = (USHORT *)AllocMem((long)sizeof(USHORT) * bars,
MEMF_PUBLIC)) != 0L ) log = log | S1;
if ((csum = (ULONG *)AllocMem((long)sizeof(ULONG) * bars,
MEMF_PUBLIC)) != 0L ) log = log | S8;
if ((oldcsum = (ULONG *)AllocMem((long)sizeof(ULONG) * bars,
MEMF_PUBLIC)) != 0L ) log = log | SA;
if (log != SOK) { /* bail out if we didn't get an allocation */
wrack_sploot() ;
things_are_cool = FALSE ; /* tell _main that we're leaving */
}
e_text.TopEdge = barb + BORDER ; /* set the E text position */
intsig = FALSE ;
}
}
void handle_MESSAGES() {
unsigned long class;
unsigned int code, qual;
#ifdef TALKTOREXX
/* Wait ( (1L << window->UserPort->mp_SigBit) | rexxbit) ;
* Gosh, folks, if we do this, we get nothing else done.
* So we have to figure out how to drop in and look for Intuition
* and Rexx messages without having to hang around. In previous
* versions of this program we just crashed through the door and
* attempted to pick up messages. Methinks these days that's not
* such a good idea. Better look for a signal bit first. Any sig
* bit will do, we just need one to help our interaction with Exec
* to stay atomic.
*/
if ( ( 1L << window->UserPort->mp_SigBit ) | rexxbit ); {
dispRexxPort() ;
#else
if ( 1L << window->UserPort->mp_SigBit ) ; {
#endif
while ((NewMessage=(struct IntuiMessage *)GetMsg(window->UserPort))
!= 0L) {
class = NewMessage->Class ;
code = NewMessage->Code ;
qual = NewMessage->Qualifier ;
ReplyMsg ;
ticker = 0 ; /* cut short the timer to expedite service */
switch( class ) {
case MENUPICK:
handle_MENUPICK( class, code ) ; /* do menus ASAP */
break ;
case NEWSIZE:
intsig = TRUE ; /* resize when done here */
break ;
}
}
}
}
void memmometer() /* this subprogram draws the bar graphs */
{
long i;
long y;
(void) handle_MESSAGES() ; /* go see if the user wants anything */
i = 0 ;
while ((i < barh) && (intsig == FALSE)) {
y = barb - i ;
SetAPen(window->RPort, (long)cell[i]);
Move(window->RPort, xl, y);
Draw(window->RPort, xr, y);
i++ ;
}
}
void shake() /* this subprogram slings down the mercury column */
{
int i;
for (i = 0; i < barh; i++) {
cell[i] = WHTP ;
}
}
void lockout() /* this subprogram renders a whole column in border colors */
{
(void) handle_MESSAGES() ; /* go see if the user wants anything */
if (intsig == FALSE) {
SetAPen(window->RPort, BORP) ; /* set in the border color */
RectFill(window->RPort, xl, (barb - barh + 1), xr, barb) ; /* fill */
}
}
void updatewarps( wf, membase, memseg ) /* this subprogram finds changes */
short wf;
long membase, memseg ;
{
register long i ;
register ULONG r ;
register ULONG delta ;
register ULONG *a ;
if (memseg == 0) {
(void) lockout() ;
return ;
}
else (void) shake() ;
delta = (ULONG)(memseg & EVENMASK) ; /* try to avoid odd address trap */
r = (ULONG)(membase & EVENMASK) ; /* prefer wrong address to death */
for (i = 0; i < barh; i++) {
csum[i] = 0 ;
}
for (i = 0; i < barh; i++) {
for (a = (ULONG *)r; a < (ULONG *)(r + delta); a++) {
csum[i] ^= *a ;
}
if (oldcsum[i] != 0) cell[i] ^= 4L ; /* enters with pens */
if (csum[i] == oldcsum[i]) cell[i] &= 4L ; /* all on, condition */
if (csum[i] == 0) cell[i] ^= 6L ; /* detected clears a */
if (oldcsum[i] == 0xffffffff) cell[i] = 6L ; /* pen; at the end a */
if (csum[i] == 0xffffffff) cell[i] = 4L ; /* logical true sets */
oldcsum[i] = csum[i] ; /* a pen not yet set */
r += delta ;
}
(void) memmometer();
}
void updatescreen( wf, membase, memseg )
short wf;
long membase, memseg;
{
register long size ;
register struct MemHeader *hdr ;
register struct MemChunk *chunk ;
extern struct ExecBase *SysBase ;
register long *which ; /* active memlist chunk pointer */
register long newlimit ; /* number of chunks, incl 1 null chunk, + 1 */
register long newfrags ; /* number of chunks, incl null chunks, + 1 */
long newsize ; /* size of next request for chunkv/sizev memory, + 1 */
int i, j, k, l ;
int length ; /* length is number of chunks to be processed, + 1 */
BOOL cf, nf ; /* cf is "chip flag" nf is "null chunk found" flag */
if (memseg == 0) {
(void) lockout() ;
return;
}
else (void) shake() ;
for (i = 0; i < 3; i++) {
chip[i] = 0;
fast[i] = 0;
}
for (i = 0; i < frags; i++) {
chunkv[i] = 0;
sizev[i] = 0;
}
newfrags = 0 ;
newlimit = 0 ;
nf = FALSE;
Forbid() ;
hdr = (struct MemHeader *) SysBase->MemList.lh_Head ;
while (hdr->mh_Node.ln_Succ) {
if (hdr->mh_Attributes & MEMF_CHIP) {
which = chip ;
cf = TRUE;
}
else {
which = fast ;
cf = FALSE;
}
if (((cf == TRUE) && (wf == 0)) || ((cf == FALSE) && (wf > 0))) {
for (chunk = hdr->mh_First; chunk; chunk = chunk->mc_Next) {
if (which[1] < frags) chunkv[which[1]++] = (unsigned long)chunk ;
size = chunk->mc_Bytes ;
if (which[2] < frags) sizev[which[2]++] = (unsigned long)size;
*which += size ;
if (nf == FALSE) {
newlimit++ ;
if (chunkv[newfrags] == NULL) {
nf = TRUE;
}
}
newfrags++ ;
}
}
hdr = (struct MemHeader *)hdr->mh_Node.ln_Succ ;
}
Permit() ;
length = frags ;
if (newlimit < frags) length = newlimit ;
for (i = 0; i < length; i++) {
chunkv[i] -= membase; /* chunkv is now array offset from base */
sizev[i] += chunkv[i]; /* and sizev is now address of array top */
chunkv[i] = chunkv[i] / memseg; /* this is the number of pixels */
sizev[i] = sizev[i] / memseg; /* and this is the top pixel */
if (chunkv[i] < 0) chunkv[i] = 0 ; /* we do some bounds checking */
if (sizev[i] < 0) sizev[i] = 0 ;
if (chunkv[i] >= barh) chunkv[i] = barh - 1 ;
if (sizev[i] >= barh) sizev[i] = barh - 1 ;
if (sizev[i] - chunkv[i] < 0) sizev[i] = chunkv[i] ;
j = chunkv[i] ; /* from now on it will be less confusing if */
k = sizev[i] ; /* we assign some variables for this stuff */
if (sizev[i] - chunkv[i] == 0) {
cell[j] &= BAKP ;
}
else {
for (l = j; l < k; l++) {
cell[l] &= HLTP ;
}
}
}
(void) memmometer();
newsize = frags ;
while (newsize < newlimit) {
newsize += EXTENSION ;
}
if (newlimit > frags) {
(void) FreeMem(chunkv, (long)(sizeof(long) * frags));
if ((chunkv = (unsigned long *)AllocMem((long)sizeof(long) * newsize,
MEMF_PUBLIC)) == 0L ) {
log = log & C2 ;
}
(void) FreeMem(sizev, (long)(sizeof(long) * frags));
if ((sizev = (unsigned long *)AllocMem((long)sizeof(long) * newsize,
MEMF_PUBLIC)) == 0L ) {
(void) FreeMem(chunkv, (long)(sizeof(long) * newsize));
log = log & C4 ;
}
if (log != SOK) {
wrack_sploot() ;
things_are_cool = FALSE ;
}
else frags = newsize ;
}
}
main(argc, argv)
int argc ;
char *argv[] ;
{
static struct IntuiText bodyText0 =
{BAKP, SHAP, JAM2, 58, 10, NULL, NULL, NULL};
static struct IntuiText bodyText1 =
{BAKP, SHAP, JAM2, 42, 20, NULL, NULL, NULL};
static struct IntuiText bodyText2 =
{BAKP, SHAP, JAM2, 50, 30, NULL, NULL, NULL};
static struct IntuiText positiveText =
{BAKP, SHAP, JAM2, 7, 3, NULL, NULL, NULL};
static struct IntuiText negativeText =
{BAKP, SHAP, JAM2, 7, 3, NULL, NULL, NULL};
struct IntuiMessage *NewMessage;
ULONG class;
USHORT code;
ULONG wakeupbits;
long syspri;
char *nptr;
struct Task *mmtcb;
char oldpri;
int t;
int i;
#ifdef TALKTOREXX
/*
* Local variables for rexx
*/
int x;
char mmi[4] = "mm0";
char four[2] = "4";
#endif
USHORT colflags; /* keeps track of column positions and counts */
USHORT left; /* left column, left edge */
USHORT middle; /* middle column, left edge */
USHORT right; /* right column, left edge */
USHORT barw; /* width of each mercury column */
USHORT wf; /* memmometer window current column number */
long cmemseg;
long sfmemseg;
long fmemseg;
long membase;
long memseg;
long memsize;
bodyText0.IText = (UBYTE *) "WARNING! CRASH POSSIBLE";
bodyText1.IText = (UBYTE *) "MENU MEMORY SELECTIONS MUST";
bodyText2.IText = (UBYTE *) "REFERENCE EXISTING MEMORY";
bodyText0.NextText = &bodyText1;
bodyText1.NextText = &bodyText2;
positiveText.IText = (UBYTE *) "Risk It";
negativeText.IText = (UBYTE *) "Retreat";
log = 0 ;
if ((cell = (USHORT *)AllocMem((long)sizeof(USHORT) * BARS,
MEMF_PUBLIC)) != 0L ) log = log | S1;
if ((chunkv = (ULONG *)AllocMem((long)sizeof(ULONG) * STARTVAL,
MEMF_PUBLIC)) != 0L ) log = log | S2;
if ((sizev = (ULONG *)AllocMem((long)sizeof(ULONG) * STARTVAL,
MEMF_PUBLIC)) != 0L ) log = log | S4;
if ((csum = (ULONG *)AllocMem((long)sizeof(ULONG) * BARS,
MEMF_PUBLIC)) != 0L ) log = log | S8;
if ((oldcsum = (ULONG *)AllocMem((long)sizeof(ULONG) * BARS,
MEMF_PUBLIC)) != 0L ) log = log | SA;
if (log != SOK) {
wrack_sploot() ;
exit(AARRRGH) ;
}
if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary(
(UBYTE *)"intuition.library",33L)) != NULL &&
(window=OpenWindow(&newwindow)) != NULL) {
if ((GfxBase = (struct GfxBase *)OpenLibrary(
(UBYTE *)"graphics.library", 0L)) != NULL) {
(void) initmenus();
/* rp = window->RPort ; */
inittimer();
wf = 0;
enforcer = FALSE ; /* these are WARPS mode flags that let us */
enforced = FALSE ; /* know that we have to adjust cmembase & */
pmchange = FALSE ; /* cmemsize to avoid alarming the enforcer */
cschange = FALSE ; /* the change flags track the menu changes */
mmode = FALSE ;
mode = p_mode ;
delayval = p_rate ;
priority = p_priority ;
basepri = priority ;
syspri = priority ;
nptr = NULL ;
mmtcb = FindTask( (UBYTE *)nptr ) ;
oldpri = SetTaskPri( mmtcb, syspri ) ;
if (p_chip < 0) p_chip = 0 ;
cmemsize = p_chip << 10 ;
p_chip = cmemsize ;
if (p_chipa < 0) p_chipa = 0 ;
cmembase = p_chipa << 10 ;
p_chipa = cmembase ;
#ifndef TALKTOREXX
if ((cmembase == 0) && (mode == WARPS)) {
cmembase = 0x400 ;
if (cmemsize > 400) cmemsize -= 0x400 ;
enforced = TRUE ;
}
#endif
if (p_sf < 0) p_sf = 0 ;
sfmemsize = p_sf << 10 ;
p_sf = sfmemsize ;
if (p_sfa < 0) p_sfa = 0 ;
sfmembase = p_sfa << 10 ;
p_sfa = sfmembase ;
if (p_fast < 0) p_fast = 0 ;
if (p_fast >= 256) fmemsize = p_sf << 10 ;
else fmemsize = p_fast << 20 ;
p_fast = fmemsize ;
fmembase = 1 << 27 ;
if (p_fasta > 0) fmembase = (p_fasta << 27) ;
else if (p_fasta < 0) {
fmembase = 0x8000000 - ((-1 * p_fasta) << 20) ;
}
p_fasta = fmembase ;
#ifdef TALKTOREXX
/*
* For rexx, open up a Rexx port, and send out the first command,
* if there was one; no reason not to send it out asynchronously.
*/
refrshpre = FALSE ;
while ( ( rexxbit == 0 ) && ( mmi[2] <= four[0] ) ){
mmi[2]++ ;
rexxbit = upRexxPort(mmi, rcl, NULL, &disp) ;
}
firstcommand[0] = 0 ;
for (x=1; x<argc; x++) {
strcat(firstcommand, argv[x]) ;
strcat(firstcommand, " ") ;
}
if (firstcommand[0]) {
asyncRexxCmd(firstcommand) ;
}
#endif
/*
* Below is main's contained loop; we stay in it until we're told to quit.
*/
while (things_are_cool == TRUE) {
#ifdef TALKTOREXX
/*
* Update rexx menu presets here. No Mercy. Except for our arexx function
* pre-check with respect to range, what user asks for is what user gets.
* To avoid objection by the enforcer, base addresses need to be above 1K
* for the WARPS mode. All memory specifiers are interpreted directly as
* signed 32-bit values.
*/
if (refrshpre == TRUE) {
chgflag = TRUE ;
delayval = p_rate ;
priority = p_priority ;
basepri = priority ;
syspri = priority ;
nptr = NULL ;
mmtcb = FindTask( (UBYTE *)nptr ) ;
oldpri = SetTaskPri( mmtcb, syspri ) ;
cmemsize = p_chip ; /* user can set this to anything */
cmembase = p_chipa ;/* we allow any possible address */
mode = p_mode ; /* & user pays funeral expenses! */
sfmemsize = p_sf ;
sfmembase = p_sfa ;
fmemsize = p_fast ;
fmembase = p_fasta ;
refrshpre = FALSE ;
}
#endif
if (chgflag != 0) {
chgflag = 0 ;
colflags = 0 ;
if (cmemsize != 0) colflags = colflags | (1 << 0) ;
if (sfmemsize != 0) colflags = colflags | (1 << 1) ;
if (fmemsize != 0) colflags = colflags | (1 << 2) ;
switch ( colflags ) {
case 0: /* NO SELECTION */
barw = (WINW - (2 * BORDER)) - 1 ;
left = LEFT ;
middle = 0 ;
right = 0 ;
f_text.FrontPen = BAKP ;
break ;
case 1: /* CHIP ONLY */
barw = (WINW - (2 * BORDER)) - 1 ;
left = LEFT ;
middle = 0 ;
right = 0 ;
f_text.FrontPen = BAKP ;
break ;
case 2: /* SF ONLY */
barw = (WINW - (2 * BORDER)) - 1 ;
left = 0 ;
middle = LEFT ;
right = 0 ;
f_text.FrontPen = HLTP ;
break ;
case 3: /* CHIP & SF */
barw = ((WINW - (2 * BORDER)) / 2 ) - 1 ;
left = LEFT ;
middle = (left + barw + 1) ;
right = 0 ;
f_text.FrontPen = HLTP ;
break ;
case 4: /* FAST ONLY */
barw = (WINW - (2 * BORDER)) - 1 ;
left = 0 ;
middle = 0;
right = LEFT ;
f_text.FrontPen = BLUP ;
break ;
case 5: /* CHIP & FAST */
barw = ((WINW - (2 * BORDER)) / 2 ) - 1 ;
left = LEFT ;
middle = 0 ;
right = (left + barw + 1) ;
f_text.FrontPen = BLUP ;
break ;
case 6: /* SF & FAST */
barw = ((WINW - (2 * BORDER)) / 2 ) - 1 ;
left = 0 ;
middle = LEFT ;
right = (middle + barw + 1) ;
f_text.FrontPen = CYNP ;
break ;
case 7: /* CHIP & SF & FAST */
barw = ((WINW - (2 * BORDER)) / 3 ) - 1 ;
left = LEFT ;
middle = (left + barw + 1) ;
right = (middle + barw + 1) ;
f_text.FrontPen = CYNP ;
break ;
} /* end of switch ( colflags ) */
} /* end of if ( chgflag ) */
if (mmode == TRUE && ((sfmemsize != 0) ||
(fmemsize != 0))) {
/* Keep your eyes open here. If we get a negative */
/* response from the requester, that means either the */
/* user retreated, or a no-requester function such as */
/* noreq or KillReq has selected the negative option. */
/* If such functions select the positive option they */
/* force acceptance of the crash risk for Warps mode. */
mode = AutoRequest(window, &bodyText0, &positiveText,
&negativeText, 0L, 0L, 319L, 79L) ;
if (mode == FALSE) {
sfmemseg = 0 ; /* user Retreat selection */
sfmemsize = 0 ; /* results in execution of */
fmemseg = 0 ; /* this code segment which */
fmemsize = 0 ; /* resets to safer values */
}
}
if (pmchange == TRUE) {
if (mmode == TRUE) enforcer = TRUE ;
else if (mode == FRAGS) {
if ((cmembase = 0x400) && (enforced == TRUE)) {
cmembase = 0 ;
if (cmemsize > 0) cmemsize += 0x400 ;
}
enforcer = FALSE ;
enforced = FALSE ;
}
pmchange = FALSE ;
}
if (mmode == TRUE) {
mode = WARPS ;
mmode = FALSE ;
}
if (cschange == TRUE) {
cschange = FALSE ;
if (mode == WARPS) {
enforcer = TRUE ;
enforced = FALSE ;
}
}
if (enforcer == TRUE) {
if (cmembase == 0) cmembase = 0x400 ;
if (enforced == FALSE) {
if (cmemsize > 0x400) cmemsize -= 0x400 ;
enforced = TRUE ;
}
enforcer = FALSE ;
}
cmemseg = cmemsize / barh ;
sfmemseg = sfmemsize / barh ;
fmemseg = fmemsize / barh ;
switch ( wf ) {
case 0:
xl = left ;
membase = cmembase ;
memsize = cmemsize ;
memseg = cmemseg ;
break ;
case 1:
xl = middle ;
membase = sfmembase ;
memsize = sfmemsize ;
memseg = sfmemseg ;
break ;
case 2:
xl = right ;
membase = fmembase ;
memsize = fmemsize ;
memseg = fmemseg ;
break ;
} /* end of switch ( wf ) */
xr = xl + barw ;
if (xl != 0) {
if (intsig == TRUE) {
handle_NEWSIZE() ;
}
if (mode == WARPS) {
(void) updatewarps( wf, membase, memseg ) ;
e_text.FrontPen = WHTP ;
}
if (mode == FRAGS) {
(void) updatescreen( wf, membase, memseg ) ;
e_text.FrontPen = BAKP ;
}
}
if (syspri != priority) {
syspri = priority ;
nptr = NULL;
mmtcb = FindTask( (UBYTE *)nptr ) ;
oldpri = SetTaskPri( mmtcb, syspri ) ;
}
if (wf == 2) {
PrintIText(window->RPort,&f_text,RTEXT,0L) ;
while ( ticker > 0 ) {
wakeupbits = Wait(timerbit) ;
if (wakeupbits & timerbit) {
GetMsg(timerport);
SetTimer(0L, TMARK, timermsg);
}
/* quick like, go see if the user wants anything */
(void) handle_MESSAGES() ;
ticker-- ;
}
ticker = delayval * TICKIES ;
}
wf++ ;
if (wf >= 3) wf = 0 ;
if (intsig == TRUE) {
handle_NEWSIZE() ;
}
} /* end of while ( things_are_cool) */
if (timerport) {
Wait(timerbit);
GetMsg(timerport);
CloseDevice((struct IORequest *)timermsg);
DeleteStdIO(timermsg);
DeletePort(timerport);
}
#ifdef TALKTOREXX
/*
* With Rexx, we need to bring the port down.
*/
dnRexxPort() ;
#endif
if (GfxBase) CloseLibrary((struct Library *)GfxBase) ;
}
if (window) CloseWindow(window) ;
if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase) ;
}
wrack_sploot() ;
exit(0L) ;
}
#ifdef TALKTOREXX
/*
* Now we get into the actual code necessary for our REXX port; functions
* that do the real work. Note that this program was not structured very
* nicely for Rexx; Tom earlier wrote some of these functions, particularly
* the argument parser and argument evaluator. I did the menu functions.
* Many programs have these subroutines already in place; they are called
* as part of the event loop. This program, however, just has one big
* switch statement with different actions. It's definitely an early Amiga
* class program, my fault, of course . . .
*
* First, the locals.
*/
long args[4] ; /* what args did we see to this function? */
int parsed ; /* was argument parsing successful? */
int userreplied ; /* has current message been replied to yet? */
/*
* This function takes a pointer to a pointer to a string, grabs the
* next number, returns it, and advances the pointer to the string to
* point after the number.
*/
long getnm(where)
char **where ;
{
register char *p = *where ;
register long val = 0 ;
int gotone = 0 ;
long sign = 1 ;
while (*p <= '-' && *p) {
if (*p == '-') { /* look for a unary negative operator */
sign = -1 ;
}
p++ ;
}
while ('0' <= *p && *p <= '9') {
gotone = 1 ;
val = 10 * val + *p++ - '0' ;
}
val = sign * val ;
if (gotone == 0)
parsed = 0 ;
*where = p ;
return(val) ;
}
/*
* This function trys to find `n' numeric arguments in the command
* string, and stuffs them into the args array.
*/
void parseargs(p, n)
char *p ;
int n ;
{
register int i ;
while (*p > ' ' && *p)
p++ ;
for (i=0; i<n; i++)
args[i] = getnm(&p) ;
}
/*
* This is our main dispatch function. We check to make sure a Window
* currently exists. Then we call our handler function. If our handler
* replied, we return a 1 to indicate that. If the parse and everything
* else was successful, we return a 0. Otherwise, we return a failure
* code of 20 to indicate that the arguments were messed up.
*/
void disp(msg, dat, p)
register struct RexxMsg *msg ;
register struct rexxCommandList *dat ;
char *p ;
{
parsed = 1 ;
if (window) {
userreplied = 0 ;
((long (*)())(dat->userdata))(msg, p) ;
if (! parsed) replyRexxCmd(msg, (long)parsed, 0L, NULL) ;
else {
refrshpre = TRUE ; /* Mark Rexx request to change a preset variable */
DoCheckMenus() ; /* Remove menu checkmarks invalidated via these */
dechecked = 0 ; /* function calls, fix re-validated check marks */
rechecked = 0 ;
}
return ;
}
replyRexxCmd(msg, 20L, 10L, NULL) ;
}
/*
* This handler brings the MemMometer window to front.
*/
void rexxfront(msg, p)
struct RexxMsg *msg ;
char *p ;
{
WindowToFront(window) ;
}
/*
* This handler pushes the MemMometer window to back.
*/
void rexxback(msg, p)
struct RexxMsg *msg ;
char *p ;
{
WindowToBack(window) ;
}
/*
* This handler sets the Quit boolian.
*/
void rexxquit(msg, p)
struct RexxMsg *msg ;
char *p ;
{
things_are_cool = FALSE ;
}
/*
* This handler sets the MemMometer p_mode preset boolian. The boolian
* should be set either to FRAGS or to WARPS. Note that for safety reasons,
* this is done clandestinely, namely, any value other than "42" (WARPS) or
* "0" (FRAGS) produces a Rexx error message.
*/
void rexxmode(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 1) ;
if ( args[0] == 0 ) {
p_mode = FRAGS ;
dechecked |= 0x1 ;
rechecked = 1 ;
}
else if ( args[0] == 42 ) {
p_mode = WARPS ;
dechecked |= 0x1 ;
rechecked = 2 ;
}
else parsed = 0 ;
}
/*
* This handler sets the between-scans delay time preset variable.
*/
void rexxrate(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 1) ;
if ( ( args[0] > 0 ) && ( args[0] <= 60 ) ) {
p_rate = args[0] ;
dechecked |= 0x2 ;
}
else parsed = 0 ;
}
/*
* This handler sets the priority preset variable. Note that the range
* is greater than that allowed by the menu items. Be careful. Positive
* values greater than 20 will lock everything out so devestatingly that
* you'll have to reboot to get the system back to life.
*/
void rexxpriority(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 1) ;
if ( ( args[0] < 128 ) && ( args[0] > -128 ) ) {
p_priority = args[0] ;
dechecked |= 0x4 ;
}
else parsed = 0 ;
}
/*
* This handler sets the chip mem size preset variable.
*/
void rexxchip(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 1) ;
if ( args[0] == 0 ) {
p_chip = 0 ;
dechecked |= 0x8 ;
rechecked = TRUE ;
return ;
}
if ( ( args[0] > 0 ) && ( args[0] <= TWOMEG) ) {
p_chip = args[0] ;
dechecked |= 0x8 ;
}
else parsed = 0 ;
}
/*
* This handler sets the chip mem address preset variable. And yes,
* while it does check to see if the address is in the normal range for
* chip mem as opposed to fast mem, it does allow slow-fast mem addresses
* above the C.0 floor. If you ask for this slow-fast mem and it isn't
* there, and the WARPS mode is set, there will undoubtedly be a system
* crash, and a jolly good one at that (like, be prepared to run the
* SetClock program with the RESET option, as this program, if mismanaged
* (while in the WARPS mode) can wreak incredible violence on the hardware
* clock and maybe some other things in your custom system that nobody
* knows anything about.) If you think this is rude, remember, this is
* Rexx command stuff, and if y'all can't get in there with the big dogs,
* you'd best stay on the porch -- so use the Intuition menus instead...
*/
void rexxchipa(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 1) ;
if (( args[0] >= 0 && args[0] < TWOMEG ) || ( args[0] >= CZERO && args[0] < EZERO )) {
p_chipa = args[0] ;
dechecked |= 0x10 ;
}
else parsed = 0 ;
}
/*
* This handler sets the slow-fast mem size preset variable.
*/
void rexxsf(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 1) ;
if ( args[0] == 0 ) {
p_sf = 0 ;
dechecked |= 0x20 ;
rechecked = TRUE ;
return ;
}
if ( ( args[0] > 0 ) && ( args[0] <= EIGHTMEG ) ) {
p_sf = args[0] ;
dechecked |= 0x20 ;
}
else parsed = 0 ;
}
/*
* This handler sets the slow-fast mem address preset variable.
*/
void rexxsfa(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 1) ;
if ( ( args[0] >= TWOMEG ) && ( args[0] < EZERO ) ) {
p_sfa = args[0] ;
dechecked |= 0x40 ;
}
else parsed = 0 ;
}
/*
* This handler sets the fast mem size preset variable. Note that unlike
* with the menu, there is no bounds checking on the fast mem size requested
* through Rexx.
*/
void rexxfast(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 1) ;
if ( args[0] == 0 ) {
p_fast = 0 ;
dechecked |= 0x80 ;
rechecked = TRUE ;
return ;
}
if ( args[0] >= 0 ) {
p_fast = args[0] ;
dechecked |= 0x80 ;
}
else parsed = 0 ;
}
/*
* This handler sets the fast mem address preset variable. Note that
* unlike the menu, there is no upper address bounds checking. If you
* set this too high while in WARPS mode, it can be gone a long time
* before it gets back around to look for any messages.
*/
void rexxfasta(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 1) ;
if ( args[0] >= SEVENOH ) {
p_fasta = args[0] ;
dechecked |= 0x100 ;
}
else parsed = 0 ;
}
/*
* This handler returns the version of the MemMometer program.
*/
void rexxversion(msg, p)
struct RexxMsg *msg ;
char *p ;
{
userreplied = 1 ;
replyRexxCmd(msg, 0L, 0L, VERSION) ;
}
#endif
_cli_parse() {}
_wb_parse() {}